use std::num::ParseIntError;
use std::string::FromUtf8Error;
use bincode::error::{DecodeError, EncodeError};
use serde_json::Error;
use thiserror::Error;
use tokio::sync::oneshot::error::RecvError;
use tokio::time::error::Elapsed;

#[derive(Error, Debug)]
pub enum RpcError {
    #[error("Encode error: {0}")]
    EncodeError(#[from] Error),  // 10

    #[error("String code error: {0}")]
    StringCodeError(#[from] FromUtf8Error),   // 11

    #[error("stream error: {0}")]
    StreamError(#[from] std::io::Error),  // 12

    #[error("error, code: {error_kid:?}, message: {message:?}")]
    CustomerError{error_kid: CustomerErrorKind, message: String},

    #[error("bin decode error: {0}")]
    BinDecodeError(#[from] DecodeError),  // 13

    #[error("bin encode error: {0}")]
    BinEncodeError(#[from] EncodeError),  // 14

    #[error("parse int error: {0}")]
    ParseIntError(#[from] ParseIntError), // 15

    #[error("receive error: {0}")]
    OneshotRecvError(#[from] RecvError),  // 16

    #[error("timeout error: {0}")]
    Elapsed(#[from] Elapsed),             // 17

    #[error("std error: {0}")]
    Error(#[from] Box<dyn std::error::Error + Send>),  // 18
}

#[derive(Debug)]
pub enum CustomerErrorKind {
    Undefined,             // 0
    EncodeError,           // 10
    StringCodeError,       // 11
    StreamError,           // 12
    BinDecodeError,        // 13
    BinEncodeError,        // 14
    ParseIntError,         // 15
    OneshotRecvError,      // 16
    Elapsed,               // 17
    Error,                 // 18

    FilterIntercept,       // 被过滤器拦截
    CodecTypeNoSetError,   // 未设置编码方式
    DataError,             // 传输格式不正确
    ErrorPath,             // 错误路径
    SendError,             // 发送数据失败
    CodecTypeError,        // 编码设置错误
    StreamClose,           // 连接关闭
    TimeoutError,          // 超时
}

impl CustomerErrorKind {

    pub fn get_error_code(&self) -> i32 {
        match self {
            CustomerErrorKind::Undefined=> 0,
            CustomerErrorKind::EncodeError=> 10,
            CustomerErrorKind::StringCodeError => 11,
            CustomerErrorKind::StreamError => 12,
            CustomerErrorKind::BinDecodeError => 13,
            CustomerErrorKind::BinEncodeError => 14,
            CustomerErrorKind::ParseIntError => 15,
            CustomerErrorKind::OneshotRecvError => 16,
            CustomerErrorKind::Elapsed => 17,
            CustomerErrorKind::Error => 18,

            CustomerErrorKind::FilterIntercept => 100,
            CustomerErrorKind::CodecTypeNoSetError => 101,
            CustomerErrorKind::DataError => 102,
            CustomerErrorKind::ErrorPath => 103,
            CustomerErrorKind::SendError => 104,
            CustomerErrorKind::CodecTypeError => 105,
            CustomerErrorKind::StreamClose => 106,
            CustomerErrorKind::TimeoutError => 107,
        }
    }
}

pub fn to_customer_error(code: i32, message: String) -> RpcError {
    match code {
        0=> RpcError::CustomerError{ error_kid: CustomerErrorKind::Undefined, message },
        10=> RpcError::CustomerError{ error_kid: CustomerErrorKind::EncodeError, message },
        11 => RpcError::CustomerError{ error_kid:CustomerErrorKind::StringCodeError, message },
        12 => RpcError::CustomerError{ error_kid:CustomerErrorKind::StreamError, message },
        13 => RpcError::CustomerError{ error_kid:CustomerErrorKind::BinDecodeError, message },
        14 => RpcError::CustomerError{ error_kid:CustomerErrorKind::BinEncodeError, message },
        15 => RpcError::CustomerError{ error_kid:CustomerErrorKind::ParseIntError, message },
        16 => RpcError::CustomerError{ error_kid:CustomerErrorKind::OneshotRecvError, message },
        17 => RpcError::CustomerError{ error_kid:CustomerErrorKind::Elapsed, message },
        18 => RpcError::CustomerError{ error_kid:CustomerErrorKind::Error, message },

        100 => RpcError::CustomerError{ error_kid:CustomerErrorKind::FilterIntercept, message },
        101 => RpcError::CustomerError{ error_kid:CustomerErrorKind::CodecTypeNoSetError, message },
        102 => RpcError::CustomerError{ error_kid:CustomerErrorKind::DataError, message },
        103 => RpcError::CustomerError{ error_kid:CustomerErrorKind::ErrorPath, message },
        104 => RpcError::CustomerError{ error_kid:CustomerErrorKind::SendError, message },
        105 => RpcError::CustomerError {error_kid:CustomerErrorKind::CodecTypeError, message},
        106 => RpcError::CustomerError {error_kid:CustomerErrorKind::StreamClose, message},
        107 => RpcError::CustomerError {error_kid:CustomerErrorKind::TimeoutError, message},
        _ => RpcError::CustomerError{ error_kid:CustomerErrorKind::Undefined, message },
    }
}

pub struct RpcErrorDto {
    pub code: i32,
    pub message: String,
}

impl RpcErrorDto {
    pub fn new(code: i32, message: String) -> RpcErrorDto {
        RpcErrorDto { code, message }
    }
}

impl From<&RpcError> for RpcErrorDto {
    fn from(value: &RpcError) -> Self {
        match value {
            RpcError::EncodeError(error) => {
                RpcErrorDto::new(10, error.to_string())
            }
            RpcError::StringCodeError(error) => {
                RpcErrorDto::new(11, error.to_string())
            }
            RpcError::StreamError(error) => {
                RpcErrorDto::new(12, error.to_string())
            }
            RpcError::CustomerError { error_kid, message } => {
                RpcErrorDto::new(error_kid.get_error_code(), message.to_string())
            }
            RpcError::BinDecodeError(error) => {
                RpcErrorDto::new(13, error.to_string())
            }
            RpcError::BinEncodeError(error) => {
                RpcErrorDto::new(14, error.to_string())
            }
            RpcError::ParseIntError(error) => {
                RpcErrorDto::new(15, error.to_string())
            }
            RpcError::OneshotRecvError(error) => {
                RpcErrorDto::new(16, error.to_string())
            }
            RpcError::Elapsed(error) => {
                RpcErrorDto::new(17, error.to_string())
            }
            RpcError::Error(error) => {
                RpcErrorDto::new(18, error.to_string())
            }
        }
    }
}